package com.example.auth.Configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.builders.InMemoryClientDetailsServiceBuilder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

/**
 * 密码模式下向授权服务器请求access_token:
 * <p>
 * http://localhost:8082/oauth/token?grant_type=password&client_id=client_id&client_secret=123&scope=APPLICATION&username=Ringo&password=123
 *
 * @author Ringo
 * @date 2021/10/19 20:16
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration
        extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private PasswordEncoder passwordEncoder;

    public static final String SIGNING_KEY = "RingoTangs";

    // =============================================================================================

    /**
     * JWT Token 的转换器, 同时也是 Token Enhancer 增强器（可以添加自定义信息）
     */
    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey(SIGNING_KEY);
        return converter;
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }


    // ============================================================================================
    @Bean
    public AuthorizationServerTokenServices tokenServices() throws Exception {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setClientDetailsService(clientDetailsService());
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setTokenStore(tokenStore());
        // token enhancer(增强) 一定要写, 否则 Token 不是 JWT
        tokenServices.setTokenEnhancer(jwtAccessTokenConverter());
        return tokenServices;
    }

    @Bean
    public ClientDetailsService clientDetailsService() throws Exception {
        InMemoryClientDetailsServiceBuilder builder =
                new InMemoryClientDetailsServiceBuilder();
        return builder.withClient("client_id")
                .secret(passwordEncoder.encode("123"))
                .scopes("APPLICATION")
                .resourceIds("microservice")
                // 支持密码模式、客户端模式、刷新 token
                .authorizedGrantTypes("password", "refresh_token", "client_credentials")
                .accessTokenValiditySeconds(7200)
                .refreshTokenValiditySeconds(7200)
                .and().build();
    }


    // =================================================================================================

    /**
     * 设置向授权服务器注册的应用
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetailsService());
    }

    /**
     * 授权服务器安全配置
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
        security.checkTokenAccess("permitAll()")
                .allowFormAuthenticationForClients();
    }


    // ====================================================================================================

    @Autowired
    private AuthenticationManager authenticationManager;

    /**
     * 设置授权码存放的位置
     */
    @Bean
    public AuthorizationCodeServices authorizationCodeServices() {
        return new InMemoryAuthorizationCodeServices();
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager)
                .tokenServices(tokenServices())
                .allowedTokenEndpointRequestMethods(HttpMethod.POST)
                .authorizationCodeServices(authorizationCodeServices());
    }
}
